﻿using System;
using System.Net;
using System.Web;

namespace Klinkby
{
    /// <summary>
    /// Transparent proxy http handler that serves requests from a remote server. 
    /// Handles GET, HEAD and POST requests, and supports compression, caching and replacing content.
    /// </summary>
    /// <remarks>http://kli.dk</remarks>
    public sealed class MirrorrimHandler : IHttpAsyncHandler
    {
        #region IHttpAsyncHandler Members

        public IAsyncResult BeginProcessRequest(
            HttpContext context,
            AsyncCallback cb,
            object extraData)
        {
            var request = context.Request;
            IAsyncResult result = null;
            result = RemoteContent.Fetch(
                RemoteContent.GetUrl(request),
                request.HttpMethod,
                () => request.BinaryRead(request.ContentLength),
                (remoteResponse, result2, e) =>
                {
                    Respond(context.Response, remoteResponse, e);
                    cb(result2);
                });
            ResponseCompression.Support(context);
            return result;
        }

        public void EndProcessRequest(IAsyncResult result)
        {
            // ILB
        }

        public bool IsReusable
        {
            get
            {
                return true; // I'm stateless
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            throw new InvalidOperationException();
        }

        #endregion

        private void Respond(HttpResponse response, HttpWebResponse remoteResponse, WebException e)
        {
            if (e == null)
            {
                response.ContentType = remoteResponse.ContentType;
                if (response.IsText())
                {
                    response.Write(Replacer.ConvertText(remoteResponse));
                }
                else
                {
                    using (var stream = remoteResponse.GetResponseStream())
                    {
                        response.BinaryWrite(stream.ToByteArray());
                    }
                }
            }
            else
            {
                response.StatusCode = e.Response != null
                    ? (int)((HttpWebResponse)e.Response).StatusCode
                    : 500;
                response.StatusDescription = e.Message;
            }
        }
    }
}